package info.liuxing.okhttp.interceptor;

import okhttp3.*;
import okio.*;

import java.io.IOException;
import java.util.Objects;

/**
 * GzipInterceptor
 *
 * @author liuxing (SE)
 * @summary GzipInterceptor
 * @Copyright (c) 2017, Lianjia Group All Rights Reserved.
 * @see okhttp3.internal.http.BridgeInterceptor
 * @since 2017-12-01 01:02
 */
public class GzipRequestInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response;

        Request originalRequest = chain.request();
        if (Objects.isNull(originalRequest.header("Accept-Encoding"))) {
            response = chain.proceed(originalRequest);
        } else {
            if (Objects.nonNull(originalRequest.body())) {
                Request compressedRequest = originalRequest.newBuilder()
                        .header("Accept-Encoding", "gzip")
                        .method(originalRequest.method(), forceContentLength(gzip(originalRequest.body())))
                        .build();

                response = chain.proceed(compressedRequest);
            } else {
                response = chain.proceed(originalRequest);
            }
        }

        return response;
    }

    private RequestBody forceContentLength(final RequestBody requestBody) throws IOException {
        final Buffer buffer = new Buffer();

        requestBody.writeTo(buffer);

        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return requestBody.contentType();
            }

            @Override
            public long contentLength() {
                return buffer.size();
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                sink.write(buffer.snapshot());
            }
        };
    }

    private RequestBody gzip(final RequestBody body) {
        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return body.contentType();
            }

            @Override
            public long contentLength() {
                return -1; // We don't know the compressed length in advance!
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
                body.writeTo(gzipSink);
                gzipSink.close();
            }
        };
    }

    private ResponseBody unGzip(final ResponseBody body) {
        return new ResponseBody() {
            @Override
            public MediaType contentType() {
                return body.contentType();
            }

            @Override
            public long contentLength() {
                return -1; // We don't know the compressed length in advance!
            }

            @Override
            public BufferedSource source() {
                return null;
            }

        };
    }
}
